#include "float.h"

/* Constructor vacío. */
Float::Float()
{	
}

/* Constructor. Recibe la precisión deseada y un valor en double. */
Float::Float(int precision, long double value)
{
	_precision 	= precision;
	_mantissa 	= "";
	longDoubleToBinary(value);
	_value = binaryToLongDouble();
}

/* Destructor. */
Float::~Float()
{
	
}

const int Float::exponent() const
{
	return _exponent;	
}

const string Float::mantissa() 	const
{
	return _mantissa;
}

const int Float::precision() const
{
	return _precision;
}

const long double Float::value() const
{
	return _value;
}

const long double Float::absValue() const
{
	if (_value < 0)
		return 0 - _value;
	else
		return _value;
}

/* Operadores. */                
Float Float::operator+ (Float f)
{
	long double result = _value + f.value();
	return Float(_precision, result);
}

Float Float::operator- (Float f)
{
	long double result = _value - f.value();
	return Float(_precision, result);
}

Float Float::operator/ (Float f)
{
	long double result = _value / f.value();
	return Float(_precision, result);
}

Float Float::operator* (Float f)
{
	long double result = _value * f.value();
	return Float(_precision, result);
}

Float Float::operator^ (Float f)
{
	long double result = pow(_value, f.value());
	return Float(_precision, result);
}

/* Asignación. */
Float& Float::operator= (const Float& f)
{
	if (this == &f) 
		return *this;
		
	_precision 	= f.precision();
	_value 		= f.value();
	_exponent 	= f.exponent();
	_mantissa 	= f.mantissa();
	return *this;	
}

/* Funciones auxiliares de conversión entre tipos. */
void Float::longDoubleToBinary(long double value)
{
	int t = _precision;
	long double mant;
		
	_isNeg = (value < 0);
	int exp = 0;
	
	/* Tomar el valor absoluto.*/
	if (_isNeg)  
		mant = ((-1) * value);
	else
		mant = value;
		
	/* Normalizar la mantisa. */	
	while (mant >= 1)
	{
		mant /= 2;
        exp++;        
	}

	while (mant < 0.5 && mant != 0) 
	{
		mant *= 2;
        exp--;        
	}

	//~ /* Redondear a t dígitos significativos. */
	//~ cout.precision(t);
	//~ cout << value << " " << mant*(pow(10,t)) << " ";
	//~ mant = ceil(mant*(pow(10,t)))/pow(10,t);	
	//~ cout << mant*(pow(10,t)) << endl;
	
	_exponent = exp;
		
	while (mant > 0 and t > 0)
	{
		mant *= 2;
		
        if (mant >= 1) 
        {
			_mantissa += "1";
			mant 	  -= 1;
        } 
        else       
			_mantissa += "0";
		
		t--;
    }
	
	while (t > 0) 
	{
		_mantissa += "0";
		t--;
	}
	
	//~ cout << _mantissa << " " << _exponent << " " << endl;
}

long double Float::binaryToLongDouble()
{
	long double result, suma, aux;
	suma = 0;
	result = pow(2.0, (double)_exponent);
	//~ cout << "Res: " << result << endl;
	
	string bit;
	
	for(int i = 0; (unsigned int) i < _mantissa.size(); i++) 
	{
		bit 	=  _mantissa[i];
		aux 	= pow(2.0, (double)(-i-1));
		suma 	+= (atoi(bit.c_str()) * aux);
		
		//~ cout << "Pasando a double: " << bit << " " << aux << " " << suma << " " << endl;
	}
	
	if (_isNeg) 	
		return (-1)*(result * suma);
	else
		return (result * suma);
}
